﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using StockModel;
using Utils;

namespace Plugins.Common
{
	public class DynamicStopLossManager : PropertyChangedNotifier, IDisposable
	{
		#region Attributes

		private decimal _referenceValue;
		private bool _isInLongMode;
		private bool _started;

		private decimal _stopValue;

		private readonly ObservableCollection<Quotation> _quotationSource;

		#endregion

		#region Properties

		public decimal StopPercentage { get; set; }
		
		public decimal StopValue
		{
			get
			{
				return _stopValue;
			} 
			private set
			{
				if (_stopValue != value)
				{
					_stopValue = value;
					base.OnPropertyChanged("StopValue");
				}
			}
		}
		
		#endregion

		#region Public Methods

		public DynamicStopLossManager(decimal stopPercentage, ObservableCollection<Quotation> quotationSource)
		{
			_quotationSource = quotationSource;

			this.StopPercentage = stopPercentage;
		}

		public void Start(bool inLongMode)
		{
			if (_started)
			{
				throw new InvalidOperationException("Can not start the dynamic stop loss manager before stopping it first");	
			}

			_started = true;
			_isInLongMode = inLongMode;
			_referenceValue = _isInLongMode ? decimal.MinValue : decimal.MaxValue;

			_quotationSource.CollectionChanged += QuotationSource_CollectionChanged; // Disposed
		}

		public void Stop()
		{
			_quotationSource.CollectionChanged -= QuotationSource_CollectionChanged;
			_started = false;
		}

		#endregion

		#region Event Handlers

		private void QuotationSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
		{
			if (e.Action == NotifyCollectionChangedAction.Add)
			{
				Quotation quotation = (Quotation)e.NewItems[e.NewItems.Count - 1]; // Only take the last quotation received

				if (_isInLongMode && quotation.Buyers[0].Value > _referenceValue)
				{
					_referenceValue = quotation.Buyers[0].Value;
					this.StopValue = _referenceValue * (1 - this.StopPercentage / 100);
				}
				else if (!_isInLongMode && quotation.Sellers[0].Value < _referenceValue)
				{
					_referenceValue = quotation.Sellers[0].Value;
					this.StopValue = _referenceValue * (1 + this.StopPercentage / 100);
				}
			}
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				if (_started)
				{
					this.Stop();	
				}
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~DynamicStopLossManager()
		{
			this.Dispose(false);
		}

		#endregion
	}
}
